package cn.sciento.farm.devicemanager.gateway.uplink.service.strategy;


import cn.sciento.farm.devicemanager.common.constant.DeviceConstant;
import cn.sciento.farm.devicemanager.common.constant.RedisConstant;
import cn.sciento.farm.devicemanager.common.util.RedisUtil;
import cn.sciento.farm.devicemanager.dao.entity.*;
import cn.sciento.farm.devicemanager.gateway.downlink.DelayManager;
import cn.sciento.farm.devicemanager.gateway.downlink.MqttDataFactory;
import cn.sciento.farm.devicemanager.gateway.downlink.service.MqttBlockedSendManager;
import cn.sciento.farm.devicemanager.gateway.downlink.service.impl.MqttSendService;
import cn.sciento.farm.devicemanager.gateway.model.downlink.BaseBlockControlData;
import cn.sciento.farm.devicemanager.gateway.model.downlink.SciGatewayConfigData;
import cn.sciento.farm.devicemanager.gateway.uplink.service.base.LogTaskFactory;
import cn.sciento.farm.devicemanager.service.ControllerService;
import cn.sciento.farm.devicemanager.service.StrategyService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalTime;
import java.util.List;

/**
 * @author wumu
 * @version V1.0
 * @date 3/21/18
 * @time 8:40 PM
 */
@Slf4j
@Service
public class StrategyDisposeServiceImpl implements StrategyDisposeService {

    private final Long INTERVAL_TIME = 60*6L;

    @Autowired
    private ControllerService controllerService;

    @Autowired
    private StrategyService strategyService;


    @Autowired
    private MqttBlockedSendManager blockedSendManager;

    @Autowired
    private MqttSendService mqttSendService;

    /**
     * 实现逻辑
     * 1. 当有异常数据发送上来的时候，检查5分钟之内是否超过三次，没有则下发刷新数据，有则处理逻辑
     * 2. 需要连续异常的数据才能够触发
     */
    @Override
    public void changeDeviceData(DevCollection deviceCollection, float data) {
        // 获取策略
        List<DevStrategy> switchStrategyList = strategyService.getByCollectionId(deviceCollection.getId());
        if (switchStrategyList == null || switchStrategyList.size() == 0) {
            return;
        }
        LocalTime localTime = LocalTime.now();
        log.info("开始处理策略");
        // 处理策略
        for (DevStrategy switchStrategy : switchStrategyList) {

                // 判断策略的生效时间
                Integer beginTime = switchStrategy.getBeginTime();
                Integer endTime = switchStrategy.getEndTime();
                if(beginTime != null && endTime != null){
                    LocalTime beginLocalTime = LocalTime.ofSecondOfDay(beginTime);
                    LocalTime endLocalTime = LocalTime.ofSecondOfDay(endTime);
                    if(localTime.isBefore(beginLocalTime) || localTime.isAfter(endLocalTime)){
                        continue;
                    }
                }

                StringBuilder content = new StringBuilder("");
                boolean en = judgeStrategy(deviceCollection, switchStrategy, data, content);
                log.info("策略是否生效："+en);

                if (en) {
                    // 10分钟
                    RedisUtil.putCacheStr(RedisConstant.STRATEGY_INTERVAL_PREFIX + switchStrategy.getId(), "", INTERVAL_TIME);
                    DevController deviceSwitch = controllerService.getById(switchStrategy.getControllerId());
                    content = content.append(deviceSwitch.getName());
                    if (deviceSwitch == null) {
                        continue;
                    }
                    sendMqtt(content.toString(), deviceSwitch, switchStrategy);
                }


        }
    }

    private boolean judgeStrategy(DevCollection deviceCollection, DevStrategy switchStrategy, float data, StringBuilder conent) {
        String alarmType = switchStrategy.getType();
        Float threshold = switchStrategy.getThreshold();
        String action = switchStrategy.getAction() == 1 ? "开启" : "关闭";

        boolean effect = false;

        switch (alarmType) {
            case DeviceConstant.STRATEGY_TYPE_BIGGER:
                boolean greaterTrigger = data > threshold;
                effect = isEffect(deviceCollection, switchStrategy, greaterTrigger);
                conent = conent.append(
                        "采集设备(" +
                                deviceCollection.getName() +
                                ")在值大于" +
                                threshold +
                                "时" +
                                action
                );
                break;
            case DeviceConstant.STRATEGY_TYPE_SMALLER:
                boolean lessTrigger = data < threshold;
                effect = isEffect(deviceCollection, switchStrategy, lessTrigger);
                conent = conent.append(
                        "采集设备(" +
                                deviceCollection.getName() +
                                ")在值小于" +
                                threshold +
                                "时" +
                                action
                );
                break;
            default:
        }
        return effect;

    }

    // todo 加入时间间隔
    private boolean isEffect(DevCollection deviceCollection, DevStrategy switchStrategy, boolean trigger) {
        if (trigger) {
            String intervalEffect = RedisUtil.getCacheStr(RedisConstant.STRATEGY_INTERVAL_PREFIX + switchStrategy.getId());
            if(intervalEffect == null){
                log.info("触发了一次" + switchStrategy);
                RedisUtil.incr(RedisConstant.STRATEGY_EXCEED_PREFIX + switchStrategy.getId());
                Long frequency = RedisUtil.incr(RedisConstant.STRATEGY_EXCEED_PREFIX + switchStrategy.getId(),60*3L);
                //连续三次超过阀值触发策略
                if (frequency >= 2) {
                    log.info("触发了策略" + switchStrategy);
                    RedisUtil.cleanRedisByKey(RedisConstant.STRATEGY_EXCEED_PREFIX + switchStrategy.getId());
                    return true;

                }else {
                    // 下发刷新数据
                    refreshSensor(deviceCollection);
                }
            }

        } else {
            RedisUtil.cleanRedisByKey(RedisConstant.STRATEGY_EXCEED_PREFIX + switchStrategy.getId());
        }
        return false;
    }

    void refreshSensor(DevCollection deviceCollection){
        SciGatewayConfigData sciGatewayConfigData = new SciGatewayConfigData();
        sciGatewayConfigData.setRefresh(1);
        sciGatewayConfigData.setConcentrator(deviceCollection.getEui());
        mqttSendService.send(sciGatewayConfigData.generate());
    }

    void sendMqtt(String content, DevController deviceSwitch, DevStrategy switchStrategy) {
        log.info("策略触发发送下发控制" + switchStrategy);
        int maxDuration = deviceSwitch.getDuration();
        int duration = switchStrategy.getDuration();
        if (maxDuration != 0 && duration > maxDuration) {
            duration = maxDuration;
        }
        BaseBlockControlData abstractBlockData = MqttDataFactory.getMqttDataFactory()
                .createData(deviceSwitch.getProtocol(), MqttDataFactory.BLOCK_CONTROL);
        abstractBlockData.setConcentrator(deviceSwitch.getEui());
        abstractBlockData.setNode(deviceSwitch.getNode());
        abstractBlockData.setCircuit(deviceSwitch.getCircuit());
        abstractBlockData.setEn(switchStrategy.getAction());
        abstractBlockData.setDuration(duration);

        int count = blockedSendManager.send(abstractBlockData).getCode();


        long time = System.currentTimeMillis();
        // 储存开关日志
        DevControllerLog switchLog = new DevControllerLog();
        switchLog.setControllerId(deviceSwitch.getId());
        switchLog.setName(deviceSwitch.getName());
        switchLog.setAction(switchStrategy.getAction());
        switchLog.setDuration(duration);
        switchLog.setResult(count);
        switchLog.setTenantId(deviceSwitch.getTenantId());
        switchLog.setStartTime(time);
        switchLog.setType(DeviceConstant.STRATEGY_CONTROL);
        DelayManager.getInstance().executeLog(LogTaskFactory.saveControllerLog(switchLog));


        // 储存策略触发的日志
        DevStrategyLog switchStrategyLog = new DevStrategyLog();
        switchStrategyLog.setStrategyId(switchStrategy.getId());
        switchStrategyLog.setResult(count);
        switchStrategyLog.setStartTime(time);
        switchStrategyLog.setControllerId(deviceSwitch.getId());
        switchStrategyLog.setName(deviceSwitch.getName());
        switchStrategyLog.setContent(content);
        switchStrategyLog.setTenantId(deviceSwitch.getTenantId());
        DelayManager.getInstance().executeLog(LogTaskFactory.saveStrategyLog(switchStrategyLog));
    }

}
